Skip to content

docs: RFC to formalize node termination contract - #3256

Open
ketanjani21 wants to merge 1 commit into
kubernetes-sigs:mainfrom
ketanjani21:formalize-node-termination-contract
Open

docs: RFC to formalize node termination contract#3256
ketanjani21 wants to merge 1 commit into
kubernetes-sigs:mainfrom
ketanjani21:formalize-node-termination-contract

Conversation

@ketanjani21

Copy link
Copy Markdown
Contributor

Fixes: #3029

Description

Formalizes the node termination flow as a design doc under designs/, following the pattern set by #3192. This changes no observable behavior — it documents what already exists.

Termination has multiple entry points (Node delete, NodeClaim delete, expiration, disruption, node/health) converging on the same controller chain, but the contract between them lives implicitly across four packages (node/termination, terminator, nodeclaim/lifecycle, node/health). Reconstructing that contract from code has produced recurring grace-period correctness bugs (#3032, #3111) and adds review overhead on every termination-touching PR (see the review history on #3063). Derek's node-repair RFC (#3192) explicitly names this contract as a follow-up dependency.

The RFC covers:

  • Trigger and inputs — what the flow requires, what may be absent.
  • Sources of nodeclaim-termination-timestamp — the two writers (nodeclaim/lifecycle and node/health), their intents, and the write-ordering invariant that makes the deadline monotone (it can only get tighter, never looser).
  • Status condition progressionDrainedVolumesDetachedInstanceTerminating, with reasons and transition triggers.
  • Guarantees — eight guarantees the flow makes to its callers, including PDB respect, tier ordering, grace-period clamping, and idempotent instance termination.
  • Edge cases — the exhaustive table (missing NodeClaim, duplicate NodeClaims, fast-path bypass, past-deadline behavior, race between the two annotation writers, etc.).
  • Non-goals and follow-ups — the annotation-to-field migration and writer consolidation are named as follow-ups; both preserve rather than replace this contract.

Kept single-purpose intentionally. A companion package-level pkg/controllers/node/termination/doc.go pointing to this RFC is proposed as a follow-up PR so a contributor grepping the code discovers the contract next to it.

How was this change tested?

N/A — design document only.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

LLMs were used in the writing of this document, but the contribution is mine.

@kubernetes-prow kubernetes-prow Bot added the do-not-merge/invalid-commit-message Indicates that a PR should not merge because it has an invalid commit message. label Aug 22, 2026
@kubernetes-prow

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: ketanjani21
Once this PR has been reviewed and has the lgtm label, please assign tzneal for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubernetes-prow kubernetes-prow Bot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Aug 22, 2026
@kubernetes-prow
kubernetes-prow Bot requested a review from tallaxes August 22, 2026 21:48
@kubernetes-prow kubernetes-prow Bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Aug 22, 2026

Node termination is one of Karpenter's oldest and most trafficked flows. Multiple entry points funnel into it — user `Node`/`NodeClaim` deletion, expiration, disruption (consolidation, drift), and health-driven forceful termination — and the same set of controllers coordinate through implicit, code-only conventions to drain pods, wait for volumes to detach, and terminate the underlying cloud instance. There is no single place that names the flow's inputs, its status-condition progression, or the guarantees it makes to callers.

This RFC formalizes that contract as a durable design document. It changes **no observable behavior**. It catalogs what the flow already does, sequences the status conditions it drives, enumerates its guarantees and edge cases, and disambiguates the two ways the `karpenter.sh/nodeclaim-termination-timestamp` annotation gets set. Its purpose is to make the flow legible enough that termination changes stop being expensive to review and grace-period correctness bugs stop being expensive to find.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hope I'm not yanking you around, but we should make karpenter.sh/nodeclaim-termination-timestamp a validated field in the status of the nodeclaim similar to #2889

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the feedback and not yanking me around at all, this is very helpful. I saw you closed #2889 and linked #3029 there

On the open question you raised on #2889 ("if terminationTimestamp can be extended or if can only be reduced"): the RFC already answers this in the "Invariant (write ordering)" section. The annotation can only get tighter, never looser. nodeclaim/lifecycle skips its write if the annotation is already set; node/health refuses to overwrite an existing past-time value. So the deadline only monotonically tightens (can be reduced, cannot be extended).

Reading your comment as an ask to fold the field migration into this RFC:

  1. Add Status.TerminationTime *metav1.Time on NodeClaim, matching feat: surface nodeclaim termination timestamp in status #2889's shape.
  2. Both nodeclaim/lifecycle and node/health write the field alongside the existing
    annotation.
  3. Downstream consumers (terminator, health controller) read the field.
  4. Validation: kubebuilder +kubebuilder:validation:Format=date-time. Monotone-tighten
    enforced by the writing controllers per the RFC's existing invariant; a validating webhook would be stronger but not strictly required if we trust the two writers.
  5. Migration: annotation kept for one release for backward compat, then removed.

Will fold this in and reference #2889 as prior art. Should the RFC cover the annotation
deprecation timeline too, or leave that to a follow-up graduation PR? Once the RFC is
accepted, do you want the implementation carried on the same PR, or a separate
implementation PR?

@ketanjani21
ketanjani21 force-pushed the formalize-node-termination-contract branch from f537508 to 6cd48f5 Compare August 25, 2026 22:16
@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 32905365553

Coverage remained the same at 83.025%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 20896
Covered Lines: 17349
Line Coverage: 83.03%
Coverage Strength: 94216.46 hits per line

💛 - Coveralls

@ketanjani21
ketanjani21 requested a review from DerekFrank August 25, 2026 23:04
Formalizes the node termination flow's inputs, status-condition
progression, guarantees, and edge cases as a durable design document.
Changes no observable behavior.

The termination flow has multiple entry points (Node delete, NodeClaim
delete, expiration, disruption, health) converging on the same
controller chain, but the contract between them lives implicitly across
four packages. Reconstructing it from code has produced recurring
grace-period correctness bugs (kubernetes-sigs#3032, kubernetes-sigs#3111) and adds review overhead
on every termination-touching PR (kubernetes-sigs#3063). Derek's node-repair RFC
(kubernetes-sigs#3192) explicitly depends on this contract as a follow-up.

The RFC is intentionally scope-limited: it documents what already
exists. Migrating the nodeclaim-termination-timestamp annotation to a
first-class field and consolidating its two writers are named as
follow-ups; both preserve rather than replace this contract.

Fixes: kubernetes-sigs#3029
@ketanjani21
ketanjani21 force-pushed the formalize-node-termination-contract branch from 6cd48f5 to cf55536 Compare August 27, 2026 16:21
@kubernetes-prow

Copy link
Copy Markdown

Invalid commit message issues detected

Invalid commit messages

Keywords which can automatically close issues and hashtag(#) mentions are not allowed.

  • cf55536 docs: RFC to formalize node termination contract

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. do-not-merge/invalid-commit-message Indicates that a PR should not merge because it has an invalid commit message. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Formalize Node Termination Contract

3 participants